package eu.hgross.blaubotcam.video;
import java.io.ByteArrayOutputStream;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.util.Log;
/**
* http://stackoverflow.com/questions/5272388/extract-black-and-white-image-from-android-cameras-nv21-format
*
* @author Henning Gross {@literal (mail.to@henning-gross.de)}
*
*/
public class ImageUtils {
private static final String LOG_TAG = "ImageUtils";
public static byte[] convertToGrayScaleJpeg(byte[] yuv_nv21_data, int previewSizeWidth, int previewSizeHeight, int quality) {
ByteArrayOutputStream jpgOut = new ByteArrayOutputStream();
int[] imagePixelsRGB = new int[yuv_nv21_data.length];
applyGrayScale(imagePixelsRGB, yuv_nv21_data, previewSizeWidth, previewSizeHeight);
Bitmap bmap = Bitmap.createBitmap(imagePixelsRGB, previewSizeWidth, previewSizeHeight, Bitmap.Config.ARGB_8888);
if (bmap.compress(CompressFormat.JPEG, quality, jpgOut)) {
return jpgOut.toByteArray();
} else {
Log.e(LOG_TAG, "Failed to compress preview image to grayscale jpeg.");
return null;
}
}
public static byte[] convertToJpeg(byte[] yuv_nv21_data, int previewSizeWidth, int previewSizeHeight, int quality) {
ByteArrayOutputStream jpgOut = new ByteArrayOutputStream();
int[] imagePixelsRGB = convertYUV420_NV21toRGB8888(yuv_nv21_data, previewSizeWidth, previewSizeHeight);
Bitmap bmap = Bitmap.createBitmap(imagePixelsRGB, previewSizeWidth, previewSizeHeight, Bitmap.Config.ARGB_8888);
imagePixelsRGB = null;
if (bmap.compress(CompressFormat.JPEG, quality, jpgOut)) {
return jpgOut.toByteArray();
} else {
Log.e(LOG_TAG, "Failed to compress preview image to jpeg.");
return null;
}
}
public static Bitmap bitmapFromYUV(int[] pixels, int width, int height) {
Bitmap bm = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
return bm;
}
public static Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
/**
* Converts YUV420 NV21 to Y888 (RGB8888). The grayscale image still holds 3 bytes on the pixel.
*
* @param pixels output array with the converted array o grayscale pixels
* @param data byte array on YUV420 NV21 format.
* @param width pixels width
* @param height pixels height
*/
public static void applyGrayScale(int [] pixels, byte [] data, int width, int height) {
int p;
int size = width*height;
for(int i = 0; i < size; i++) {
p = data[i] & 0xFF;
pixels[i] = 0xff000000 | p<<16 | p<<8 | p;
}
}
/**
* Converts YUV420 NV21 to RGB8888
*
* @param data byte array on YUV420 NV21 format.
* @param width pixels width
* @param height pixels height
* @return a RGB8888 pixels int array. Where each int is a pixels ARGB.
*/
public static int[] convertYUV420_NV21toRGB8888(byte [] data, int width, int height) {
int size = width*height;
int offset = size;
int[] pixels = new int[size];
int u, v, y1, y2, y3, y4;
// i percorre os Y and the final pixels
// k percorre os pixles U e V
for(int i=0, k=0; i < size; i+=2, k+=2) {
y1 = data[i ]&0xff;
y2 = data[i+1]&0xff;
y3 = data[width+i ]&0xff;
y4 = data[width+i+1]&0xff;
u = data[offset+k ]&0xff;
v = data[offset+k+1]&0xff;
u = u-128;
v = v-128;
pixels[i ] = convertYUVtoRGB(y1, u, v);
pixels[i+1] = convertYUVtoRGB(y2, u, v);
pixels[width+i ] = convertYUVtoRGB(y3, u, v);
pixels[width+i+1] = convertYUVtoRGB(y4, u, v);
if (i!=0 && (i+2)%width==0)
i+=width;
}
return pixels;
}
private static int convertYUVtoRGB(int y, int u, int v) {
int r,g,b;
r = y + (int)1.402f*v;
g = y - (int)(0.344f*u +0.714f*v);
b = y + (int)1.772f*u;
r = r>255? 255 : r<0 ? 0 : r;
g = g>255? 255 : g<0 ? 0 : g;
b = b>255? 255 : b<0 ? 0 : b;
return 0xff000000 | (b<<16) | (g<<8) | r;
}
}